package k8.text;

import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.imageio.ImageIO;

import k8.Texture;

import org.lwjgl.opengl.GL11;

public final class Font extends Texture {

    // Array of glyph metrics
    private GlyphMetrics[] metrics;

    /**
     * Creates a new instance of Font
     * 
     * @throws IOException
     */
    public Font(String name) throws Exception {
        BufferedImage bin;
        BufferedImage bgr;
        InputStream is;
        String buf;
        int size, c, x, y, w, h, a;

        // Open an input stream on the named font file
        is = this.getClass().getResourceAsStream(name);

        // Attempt to read the binary image
        bin = ImageIO.read(is);
        size = bin.getWidth();

        // Convert binary to blue/green/red
        bgr = new BufferedImage(size, size, BufferedImage.TYPE_3BYTE_BGR);
        Graphics2D g = (Graphics2D) bgr.getGraphics();
        g.drawImage(bin, null, 0, 0);

        // Obtain a data input stream of the rest of the data
        DataInputStream in = new DataInputStream(is);

        // Find "FTX" marker at beginning of metrics
        buf = "";
        do {
            buf += (char) in.read();
        } while (in.available() > 0 && !buf.endsWith("FTX"));

        // Throw an exception if we couldn't find the marker
        if (!buf.endsWith("FTX")) {
            in.close();
            throw new Exception(
                    "Could not find glyph metrics at end of specified image "
                            + name);
        }

        // Initialise the metrics array
        metrics = new GlyphMetrics[127];

        // Read each glyphs metrics
        while (in.available() > 0) {
            c = in.read();
            x = in.readInt();
            y = in.readInt();
            w = in.read();
            h = in.read();
            a = in.read();
            metrics[c] = new GlyphMetrics();
            metrics[c].width = w;
            metrics[c].ascent = a;
            metrics[c].descent = a - h;
            metrics[c].u1 = (float) (x + 1) / size;
            metrics[c].u2 = (float) (x + w - 1) / size;
            metrics[c].v1 = (float) (y + 1) / size;
            metrics[c].v2 = (float) (y + h - 1) / size;
        }

        in.close();

        // Space character isn't in texture use '_' metrics
        metrics[32] = new GlyphMetrics();
        metrics[32].width = metrics[95].width;
        metrics[32].ascent = 0;
        metrics[32].descent = 0;
        metrics[32].u1 = 0;
        metrics[32].u2 = 0;
        metrics[32].v1 = 0;
        metrics[32].v2 = 0;

        // Generate the texture
        generate(bgr, GL11.GL_INTENSITY);
    }

    /** Get GlyphMetrics for specified character. */
    public GlyphMetrics getGlyphMetrics(int codePoint) {
        // Return space metrics if specified character has none
        if (metrics[codePoint] == null)
            return metrics[32];
        return metrics[codePoint];
    }

}
